/*!
 * \file t3_core.c
 *
 * \brief weblogic t3数据包解析
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 2.0
 * \author wuwk
 * \date 2015/11/20
 *
 */
#include <stdlib.h>
#include <stdio.h>

#include "frservice_comm.h"
#include "frmem.h"
#include "frcomm.h"
#include "frhash2.h"
#include "frct_comm.h"

#include "t3_core.h"
#include "t3_analysis.h"
#include "config.h"

#define T3_REPORT_KEY_QUEUE               APM_REPORT_KEY_SESSION ".mq.queue"
#define T3_REPORT_KEY_TOPIC               APM_REPORT_KEY_SESSION ".mq.topic"
#define T3_REPORT_KEY_WEBL_SERVER         APM_REPORT_KEY_SESSION ".mq.weblogic.server"
#define T3_REPORT_KEY_WEBL_JMS_SERVER     APM_REPORT_KEY_SESSION ".mq.weblogic.jms.server"
#define T3_REPORT_KEY_WEBL_JMS_MODULE     APM_REPORT_KEY_SESSION ".mq.weblogic.jms.module"

#define T3_LINEEND                        "\x0a"

extern void *g_p_apm_context;

/*!
 * t3长连接判断
 *
 */
FR_STATIC int __ist3_longconn(Conntrack *p_st_conn, char *p_data, unsigned int ui_data_len)
{
    char arr_tmp[5];
    char *p_tmp = NULL;
    uint32_t *p_u32 = 0;
    unsigned int ui_code1 = 0;
    unsigned int ui_code2 = 0;

    if (ui_data_len < 49)
        return 0;

    // 65
    if (*(p_data + 5) != 101)
        return 0;

    memset(arr_tmp, 0x00, sizeof(arr_tmp));
    p_tmp = p_data + 33;
    memcpy(arr_tmp, p_tmp, 4);
    p_u32 = (uint32_t *)arr_tmp;
    ui_code1 = ntohl(*p_u32);

    p_tmp = p_data + 39;
    if (*p_tmp != 1 && *p_tmp != 2 && *p_tmp != 3 && *p_tmp != 4 && *p_tmp != 5 && *p_tmp != 6)
        return 0;

    p_tmp = p_data + 45;
    memcpy(arr_tmp, p_tmp, 4);
    p_u32 = (uint32_t *)arr_tmp;
    ui_code2 = ntohl(*p_u32);

    if (ui_code1 != ui_code2)
        return 0;

    return 1;
}

/*!
 * t3请求判断
 *
 */
FR_STATIC int __ist3_req(Conntrack *p_st_conn, char *p_data, unsigned int ui_data_len)
{
    char *p_line1 = NULL;
    char *p_line2 = NULL;
    unsigned int ui_line = ui_data_len;

    if (ui_data_len >= 3 && strncmp(p_data, "t3 ", 3) != 0)
        return 0;

    // 换行
    p_line1 = frmemstr(p_data, ui_data_len, (char *)T3_LINEEND, 1);
    if (p_line1 == NULL)
        return 0;
    ui_line -= (p_line1 - p_data);

    if (ui_line > 3 && strncmp(p_line1+1, "AS:", 3) == 0)
    {
        p_line2 = frmemstr(p_line1+1, ui_line-1, (char *)T3_LINEEND, 1);
        if (p_line2 == NULL)
            return 0;

        ui_line -= (p_line2 - p_line1);
        if (ui_line > 6 && strncmp(p_line2+1, "HL:19\n", 6) == 0)
            return 1;
        else
            return 0;
    }

    return 0;
}

/*!
 * t3响应判断
 *
 */
FR_STATIC int __ist3_resp(Conntrack *p_st_conn, char *p_data, unsigned int ui_data_len)
{
    char *p_line1 = NULL;
    char *p_line2 = NULL;
    unsigned int ui_line = ui_data_len;

    if (ui_data_len == 4 && strncmp(p_data, "HELO", 4) == 0)
        return 1;
    else if (ui_data_len >=3 && strncmp(p_data, "AS:", 3) == 0)
    {
        // 换行
        p_line1 = frmemstr(p_data, ui_data_len, (char *)T3_LINEEND, 1);
        if (p_line1 == NULL)
            return 0;

        ui_line -= (p_line1 - p_data);

        if (ui_line > 6 && strncmp(p_line1+1, "HL:19\n", 6) == 0)
            return 1;
        else
            return 0;
    }
    else if (ui_data_len >= 5 && strncmp(p_data, "HELO:", 5) == 0)
    {
        // 换行
        p_line1 = frmemstr(p_data, ui_data_len, (char *)T3_LINEEND, 1);
        if (p_line1 == NULL)
            return 0;

        ui_line -= (p_line1 - p_data);
        if (ui_line > 3 && strncmp(p_line1+1, "AS:", 3) == 0)
        {
            p_line2 = frmemstr(p_line1+1, ui_line-1, (char *)T3_LINEEND, 1);
            if (p_line2 == NULL)
                return 0;

            ui_line -= (p_line2 - p_line1);
            if (ui_line > 6 && strncmp(p_line2+1, "HL:19\n", 6) == 0)
                return 1;
            else
                return 0;
        }
    }

    return 0;
}

FR_STATIC void __t3_free_fragment(L7_fragment_t3 *p_st_fragment)
{
    if (p_st_fragment == NULL)
        return;

    if (p_st_fragment->p_st_data)
       bytebuff_free(&p_st_fragment->p_st_data);

    p_st_fragment->u32_total_len = 0;
    p_st_fragment->u32_left_len = 0;

    return;
}

FR_STATIC void __t3_free_protocol_info(Protocol_info_t3 **pp_protocol_info)
{
    Protocol_info_t3 *p_protocol_info = *pp_protocol_info;

    if (p_protocol_info == NULL)
        return;

    if (p_protocol_info->p_version)
        frfree(p_protocol_info->p_version);

    frfree(p_protocol_info);

    return;
}

FR_STATIC void __t3_free_session(L7Session_t3 **pp_session)
{
    L7Session_t3 *p_session = *pp_session;

    if (p_session == NULL)
        return;

    if (p_session->p_server)
        frfree(p_session->p_server);

    if (p_session->p_queue)
        frfree(p_session->p_queue);

    if (p_session->p_title)
        frfree(p_session->p_title);

    if (p_session->p_ejbname)
        frfree(p_session->p_ejbname);

    if (p_session->p_weblogic_server)
        frfree(p_session->p_weblogic_server);

    if (p_session->p_jms_server)
        frfree(p_session->p_jms_server);

    if (p_session->p_jms_module)
        frfree(p_session->p_jms_module);

    frfree(p_session);

    return;
}

/*!
 * 请求/响应后私有数据重置
 *
 */
FR_STATIC void __t3_reset_private(L7session_t3_private *p_st_private)
{
    if (p_st_private == NULL)
        return;

    if (p_st_private->p_st_body_data_req)
        frreport_body_free(&p_st_private->p_st_body_data_req);

    if (p_st_private->p_st_body_data_resp)
        frreport_body_free(&p_st_private->p_st_body_data_resp);

    if (p_st_private->p_lst_req)
        frreport_body_l7list_free(&p_st_private->p_lst_req);

    if (p_st_private->p_lst_mq)
        frreport_body_l7list_free(&p_st_private->p_lst_mq);

    if (p_st_private->p_st_fragment)
        __t3_free_fragment(p_st_private->p_st_fragment);

    memset(&p_st_private->st_l4_trans, 0x00, sizeof(p_st_private->st_l4_trans));
    p_st_private->ui_responseid = 0;
    p_st_private->i_methodid = 0;
    p_st_private->i_responserequired = 0;
    p_st_private->i_browse_status = 0;

    return;
}


/*!
 * 私有数据创建
 *
 */
FR_STATIC L7session_t3_private* __t3_private_create(void)
{
    L7session_t3_private *p_st_private = NULL;
    L7_fragment_t3 *p_st_fragment = NULL;
    Protocol_info_t3 *p_st_protocol = NULL;
    L7Session_t3 *p_st_session = NULL;

    p_st_private = (L7session_t3_private *)frmalloc(sizeof(L7session_t3_private));
    if (p_st_private == NULL)
        return NULL;

    memset(p_st_private, 0x00, sizeof(L7session_t3_private));

    p_st_fragment = (L7_fragment_t3 *)frmalloc(sizeof(L7_fragment_t3));
    if (p_st_fragment == NULL)
    {
        frfree(p_st_private);
        return NULL;
    }
    memset(p_st_fragment, 0x00, sizeof(L7_fragment_t3));

    p_st_protocol = (Protocol_info_t3 *)frmalloc(sizeof(Protocol_info_t3));
    if (p_st_protocol == NULL)
    {
        frfree(p_st_private);
        frfree(p_st_fragment);
        return NULL;
    }
    memset(p_st_protocol, 0x00, sizeof(Protocol_info_t3));

    p_st_session = (L7Session_t3 *)frmalloc(sizeof(L7Session_t3));
    if (p_st_session == NULL)
    {
        frfree(p_st_private);
        frfree(p_st_fragment);
        frfree(p_st_protocol);
        return NULL;
    }
    memset(p_st_session, 0x00, sizeof(L7Session_t3));

    p_st_private->p_st_fragment = p_st_fragment;
    p_st_private->p_st_protocol_info = p_st_protocol;
    p_st_private->p_st_session = p_st_session;

    return p_st_private;
}

/*!
 * t3 数据包长度取得
 *
 * \param *p_data                (char                  数据包数据)
 * \param ui_data_len            (unsigned int      数据包数据长度)
 *
 * \return 0:失败\n
 *         取得的长度
 *
 */
FR_STATIC uint32_t __t3_get_len(char *p_data, unsigned int ui_data_len)
{
    char arr_tmp[5];
    uint32_t u32_len = 0;
    uint32_t *p_u32_len = 0;

    if (ui_data_len < 4)
        return 0;

    memset(arr_tmp, 0x00, sizeof(arr_tmp));
    memcpy(arr_tmp, p_data, 4);
    p_u32_len = (uint32_t *)arr_tmp;
    u32_len = ntohl(*p_u32_len);

    return u32_len;
}

FR_STATIC char *__t3_memrchr(char *p_start, char *p_end, unsigned int ui_len)
{
    char *p_tmp = NULL;
    char *p_last_dot = NULL;

    if (p_start == NULL || p_end == NULL || ui_len == 0)
        return NULL;

    while (ui_len > 0)
    {
        p_last_dot = p_tmp;
        p_tmp = frmemstr(p_start, ui_len, (char *)".", 1);
        if (p_tmp == NULL)
            break;

        ui_len = p_end - p_tmp + 1;
        p_start = p_tmp + 1;
    }

    return p_last_dot;
}

/*!
 * t3 取版本并存入session
 *
 * \param *p_data              (char   数据)
 * \param ui_data_len          (unsigned int 数据长度)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __t3_get_version(char *p_data, unsigned int ui_data_len, Protocol_info_t3 *p_st_protocol)
{
    char *p_line_end = NULL;
    char *p_last_dot = NULL;
    char arr_version[64];
    unsigned int ui_line_len = 0;
    unsigned int ui_version_len = 0;

    if (p_st_protocol == NULL || ui_data_len == 0)
        return FR_FAIL;

    p_line_end = frmemstr(p_data, ui_data_len, (char *)T3_LINEEND, 1);
    if (p_line_end == NULL)
        return FR_FAIL;

    ui_line_len = p_line_end - p_data + 1;
    p_last_dot = __t3_memrchr(p_data, p_line_end, ui_line_len);
    if (p_last_dot == NULL)
        return FR_FAIL;

    ui_version_len = p_last_dot - p_data;
    snprintf(arr_version, ui_version_len+1, "%s", p_data);

    if (p_st_protocol->p_version)
        frfree(p_st_protocol->p_version);

    p_st_protocol->p_version = frstrdup(arr_version);
    if (p_st_protocol->p_version == NULL)
        return FR_FAIL;
    p_st_protocol->ui_version_len = ui_version_len;

    return FR_SUCC;
}

/*!
 * t3 链路开始(请求)
 *
 * \param *p_st_private        (L7session_t3_private  t3私有数据)
 * \param *p_data              (char   数据)
 * \param ui_data_len          (unsigned int 数据长度)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *
 */
FR_STATIC int __t3_session_start_request(L7session_t3_private *p_st_private
                                       , char *p_data
                                       , unsigned int ui_data_len)
{
    Protocol_info_t3 *p_st_protocol = NULL;

    if (p_st_private == NULL || p_st_private->p_st_protocol_info == NULL || ui_data_len == 0)
        return APM_L7_ANALYZE_FAIL;

    p_st_protocol = p_st_private->p_st_protocol_info;

    if (strncmp(p_data, "t3 ", 3) != 0)
        return APM_L7_ANALYZE_FAIL;

    return APM_L7_ANALYZE_SUCC;
}

/*!
 * t3 链路开始(响应)
 *
 * \param *p_st_private        (L7session_t3_private  t3私有数据)
 * \param *p_data              (char   数据)
 * \param ui_data_len          (unsigned int 数据长度)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *
 */
FR_STATIC int __t3_session_start_response(L7session_t3_private *p_st_private
                                        , char *p_data
                                        , unsigned int ui_data_len)
{
    Protocol_info_t3 *p_st_protocol = NULL;
    char arr_version[64];

    if (p_st_private == NULL || p_st_private->p_st_protocol_info == NULL || ui_data_len == 0)
        return APM_L7_ANALYZE_FAIL;

    p_st_protocol = p_st_private->p_st_protocol_info;
    switch (p_st_private->i_status)
    {
        case 0:
            if (strncmp(p_data, "HELO", 4) == 0)
            {
                if (ui_data_len > 4 && *(p_data + 4) == ':')
                {
                    memset(arr_version, 0x00, sizeof(arr_version));
                    // 取版本
                    if (__t3_get_version(p_data+5, ui_data_len-5, p_st_protocol) == FR_FAIL)
                        return FR_FAIL;
                    p_st_private->is_login = 1;
                    break;
                }
                p_st_private->i_status = 1;
            }
            else
                return APM_L7_ANALYZE_FAIL;
            break;
        case 1:
            if (strncmp(p_data, ":", 1) == 0)
            {
                // 取版本
                if (__t3_get_version(p_data+1, ui_data_len-1, p_st_protocol) == FR_FAIL)
                    return FR_FAIL;

                p_st_private->i_status = 2;
            }
            else
                return APM_L7_ANALYZE_FAIL;
            break;
        case 2:
            if (strncmp(p_data, "AS:", 3) == 0 && frmemstr(p_data, ui_data_len, (char *)"HL:19", 5) != NULL)
                p_st_private->is_login = 1;
            break;
        default:
            return APM_L7_ANALYZE_FAIL;
    }

    return APM_L7_ANALYZE_SUCC;
}

/*!
 * t3 session数据添加
 *
 * \param *p_st_body_data        (Frreport_body_data  上报数据)
 * \param *p_st_body_data        (Frreport_body_data   上报链表)
 * \param *p_st_session          (L7Session_t3          连接信息)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __t3_add_session(L7session_t3_private *p_st_private
                             , Frreport_body_data *p_st_body_data
                             , L7Session_t3 *p_st_session)
{
    int i_ret = 0;

    if (p_st_body_data == NULL || p_st_session == NULL)
        return FR_FAIL;

    // 服务名
    if (p_st_session->p_server != NULL)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_SESSION_SERVER, p_st_session->p_server);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    // 队列名
    if (p_st_session->p_queue != NULL)
    {
        if (p_st_private->is_topic)
            i_ret = frreport_body_l7_add_str(p_st_body_data, T3_REPORT_KEY_TOPIC, p_st_session->p_queue);
        else
            i_ret = frreport_body_l7_add_str(p_st_body_data, T3_REPORT_KEY_QUEUE, p_st_session->p_queue);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    // 长连接时没有队列信息和title
//    if (p_st_session->p_title == NULL)
//    {
//        if (p_st_private->p_st_body_data_resp)
//        {
//            // 响应
//            if (p_st_private->is_topic)
//                snprintf(arr_title, sizeof(arr_title), "NOTIFY %s", T3_KNOWN_QUEUE);
//            else
//                snprintf(arr_title, sizeof(arr_title), "GET %s", T3_KNOWN_QUEUE);
//        }
//        else
//        {
//            // 请求
//            if (p_st_private->is_topic)
//                snprintf(arr_title, sizeof(arr_title), "PUB %s", T3_KNOWN_QUEUE);
//            else
//                snprintf(arr_title, sizeof(arr_title), "PUT %s", T3_KNOWN_QUEUE);
//        }
//
//        p_st_session->p_title = frstrdup(arr_title);
//        if (p_st_session->p_title == NULL)
//            return FR_FAIL;
//    }

    if (p_st_session->p_title != NULL)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_st_session->p_title);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    // weblogic server
    if (p_st_session->p_weblogic_server != NULL)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, T3_REPORT_KEY_WEBL_SERVER, p_st_session->p_weblogic_server);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    // weblogic jms server
    if (p_st_session->p_jms_server != NULL)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, T3_REPORT_KEY_WEBL_JMS_SERVER, p_st_session->p_jms_server);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    // weblogic jms module
    if (p_st_session->p_jms_module != NULL)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, T3_REPORT_KEY_WEBL_JMS_MODULE, p_st_session->p_jms_module);
        if (i_ret == FR_FAIL)
            return FR_FAIL;
    }

    return FR_SUCC;
}

/*!
 * t3 上报
 *
 * \param *p_st_private        (L7session_t3_private  t3私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
  * \param *p_st_packet        (Apm_packet    数据包信息)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包不完整
 *
 */
FR_STATIC int __t3_data_report(L7session_t3_private *p_st_private
                             , Conntrack *p_st_conn
                             , Frhash_header *p_st_hash_report
                             , int i_req_resp)
{
    Frreport_data *p_st_report_data = NULL;
    L4_transaction *p_st_l4_trans = NULL;

    if (p_st_private == NULL || p_st_conn == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_l4_trans = &(p_st_private->st_l4_trans);

    /* request数据上报 */
    if (i_req_resp == T3_REQUEST)
    {
        if (frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, p_st_private->i_responserequired) == FR_FAIL)
            goto err;

        /* 保存request数据 */
        p_st_private->p_lst_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_body_data_req);
        if (p_st_private->p_lst_req == NULL)
            goto err;

        /* 保存mq数据 */
        p_st_private->p_lst_mq = FRREPORT_BODY_L7LIST_CLONE_MQ(p_st_private->p_st_body_data_req);
        if (p_st_private->p_lst_mq == NULL)
            goto err;

        /* session信息添加 */
        if (__t3_add_session(p_st_private, p_st_private->p_st_body_data_req, p_st_private->p_st_session) == FR_FAIL)
            goto err;

        // 浏览消息请求等到响应后再上报
        if (p_st_private->i_browse_status != 1)
        {
            // 数据上报
            if (p_st_private->i_type == T3_SUB)
                p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_SUB);
            else
                p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
            if (p_st_report_data == NULL)
                goto err;

            if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_req) == FR_FAIL)
                goto err;
            p_st_private->p_st_body_data_req = NULL;

            if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
                goto err;
            p_st_report_data = NULL;
        }
    }
    else
    {
        if (p_st_private->i_browse_status == 2)
        {
            // 数据上报
            if (p_st_private->i_type == T3_SUB)
                p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_SUB);
            else
                p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
            if (p_st_report_data == NULL)
                goto err;

            if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_req) == FR_FAIL)
                goto err;
            p_st_private->p_st_body_data_req = NULL;

            if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
                goto err;
            p_st_report_data = NULL;
        }
        /* session信息添加 */
        if (__t3_add_session(p_st_private, p_st_private->p_st_body_data_resp, p_st_private->p_st_session) == FR_FAIL)
            goto err;

        /* 数据上报 */
        if (p_st_private->i_type == T3_NOTIFY)
            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_NOTIFY);
        else
            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
        if (p_st_report_data == NULL)
            goto err;

        if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_resp) == FR_FAIL)
            goto err;
        p_st_private->p_st_body_data_resp = NULL;

        if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto err;
        p_st_report_data = NULL;
    }
    return FR_SUCC;

err:
    if (p_st_private->p_lst_req)
        frreport_body_l7list_free(&p_st_private->p_lst_req);
    if (p_st_private->p_lst_mq)
        frreport_body_l7list_free(&p_st_private->p_lst_mq);
    if (p_st_private->p_st_body_data_req)
        frreport_body_free(&p_st_private->p_st_body_data_req);
    if (p_st_private->p_st_body_data_resp)
        frreport_body_free(&p_st_private->p_st_body_data_resp);
    if (p_st_report_data)
        frreport_data_hash(p_st_hash_report, p_st_report_data);

    return FR_FAIL;
}

/*!
 * t3 请求解析
 *
 * \param *p_st_private        (L7session_t3_private  t3私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
  * \param *p_st_packet        (Apm_packet    数据包信息)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包不完整
 *
 */
FR_STATIC int __t3_analysis_req(L7session_t3_private *p_st_private
                              , Conntrack *p_st_conn
                              , Frhash_header *p_st_hash_report
                              , Apm_packet *p_st_packet)
{
    L4_transaction *p_st_l4_trans = NULL;
    L7_fragment_t3 *p_st_fragment = NULL;
    unsigned long ul_time_diff = 0;
    int i_need_report = 0;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_conn == NULL || p_st_hash_report == NULL
        || p_st_private->p_st_fragment == NULL || p_st_packet == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_fragment = p_st_private->p_st_fragment;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    if (frlist_empty(p_st_private->p_lst_req) == FR_NO)
    {
        frreport_body_l7list_free(&p_st_private->p_lst_req);
        frreport_body_l7list_free(&p_st_private->p_lst_mq);
        if (p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);
        memset(p_st_l4_trans, 0x00, sizeof(L4_transaction));
    }

    if (p_st_private->p_st_body_data_req == NULL)
    {
        p_st_private->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_body_data_req == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    if (p_st_l4_trans->st_request_time_first_byte.tv_sec == 0
        && p_st_l4_trans->st_request_time_first_byte.tv_usec == 0)
    {
        /* 请求发起的第一个数据包时间 */
        p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

        p_st_private->ul_seq = frct_seq_increase(p_st_conn);
    }

    if (frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_req, p_st_conn) == FR_FAIL)
        goto err;

    if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
        goto err;

    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto err;

    /* 请求结束时间 */
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto err;

    /* 请求发送时间 */
    ul_time_diff = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_l4_trans->st_request_time));
    if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_time_diff) == FR_FAIL)
        goto err;

    /* 请求的字节数 */
    p_st_l4_trans->l_request_bytes = p_st_fragment->u32_total_len;
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_fragment->u32_total_len) == FR_FAIL)
        goto err;

    /* t3数据解析 */
    i_ret = t3_analysis_req(p_st_private, p_st_fragment->p_st_data, p_st_private->p_st_body_data_req, &i_need_report);
    if (i_ret == FR_SUCC)
    {
        if (i_need_report == T3_YES)
        {
            /* 数据上报 */
            i_ret = __t3_data_report(p_st_private, p_st_conn, p_st_hash_report, T3_REQUEST);
            if (i_ret == FR_FAIL)
                goto err;
        }

        return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
    }
    else if (i_ret == APM_L7_ANALYZE_TODO)
    {
        if (p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        return i_ret;
    }

err:
    if (p_st_private->p_st_body_data_req)
        frreport_body_free(&p_st_private->p_st_body_data_req);

    return APM_L7_ANALYZE_FAIL;

}

/*!
 * t3 响应解析
 *
 * \param *p_st_private        (L7session_t3_private  t3私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
  * \param *p_st_packet        (Apm_packet    数据包信息)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包不完整
 *
 */
FR_STATIC int __t3_analysis_resp(L7session_t3_private *p_st_private
                               , Conntrack *p_st_conn
                               , Frhash_header *p_st_hash_report
                               , Apm_packet *p_st_packet)
{
    L4_transaction *p_st_l4_trans = NULL;
    L7_fragment_t3 *p_st_fragment = NULL;
    unsigned long ul_time_diff = 0;
    int i_need_report = 0;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_conn == NULL || p_st_hash_report == NULL
        || p_st_private->p_st_fragment == NULL || p_st_packet == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_fragment = p_st_private->p_st_fragment;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    if (p_st_private->p_st_body_data_resp == NULL)
    {
        p_st_private->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_body_data_resp == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0
        && p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
    {
        /* 响应发起的第一个数据包时间 */
        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
    }

    i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_resp, p_st_conn);
    if (i_ret == FR_FAIL)
        goto err;

    /* 有request */
    if (p_st_l4_trans->st_request_time.tv_sec != 0 && p_st_private->p_lst_req != NULL)
    {
        if (FRREPORT_BODY_L7LIST_SET_REQ(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_req) == FR_FAIL)
            goto err;

        if (p_st_private->p_lst_mq != NULL)
        {
            if (FRREPORT_BODY_L7LIST_SET_MQ(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_mq) == FR_FAIL)
                goto err;
        }

        ul_time_diff = frtime_diff(&(p_st_l4_trans->st_request_time), &p_st_packet->st_timestamp);
        if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_time_diff) == FR_FAIL)
            goto err;
    }
    else
    {
        if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, 0) == FR_FAIL)
            goto err;
    }

    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto err;

    /* 结束时间 */
    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto err;

    /* 下载时间 */
    ul_time_diff = frtime_diff(&(p_st_l4_trans->st_response_time_first_byte), &p_st_packet->st_timestamp);
    if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_time_diff) == FR_FAIL)
        goto err;

    /* 响应的字节数 */
    p_st_l4_trans->l_response_bytes = p_st_fragment->u32_total_len;
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_fragment->u32_total_len) == FR_FAIL)
        goto err;

    /* t3数据解析 */
    i_ret = t3_analysis_resp(p_st_private, p_st_fragment->p_st_data, p_st_private->p_st_body_data_resp, &i_need_report);
    if (i_ret == FR_SUCC)
    {
        if (i_need_report == T3_YES)
        {
            /* 数据上报 */
            i_ret = __t3_data_report(p_st_private, p_st_conn, p_st_hash_report, T3_RESPONSE);
            if (i_ret == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;
        }

        __t3_reset_private(p_st_private);

        return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
    }
    else if (i_ret == APM_L7_ANALYZE_TODO)
    {
        if (p_st_private->p_st_body_data_resp)
        {
            /* 保存request数据 */
            p_st_private->p_lst_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_body_data_resp);
            if (p_st_private->p_lst_req == NULL)
                goto err;

            /* 保存mq数据 */
            p_st_private->p_lst_mq = FRREPORT_BODY_L7LIST_CLONE_MQ(p_st_private->p_st_body_data_resp);
            if (p_st_private->p_lst_mq == NULL)
            {
                frreport_body_l7list_free(&p_st_private->p_lst_req);
                goto err;
            }

            frreport_body_free(&p_st_private->p_st_body_data_resp);
        }

        return i_ret;
    }

err:
    if (p_st_private->p_st_body_data_resp)
        frreport_body_free(&p_st_private->p_st_body_data_resp);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * t3 packet解析
 *
 * \param *p_st_private        (L7session_t3_private  t3私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_packet         (Apm_packet    数据包信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 * \param *p_data              (char                  数据包数据)
 * \param ui_data_len          (unsigned int      数据包数据长度)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包不完整
 *
 */
FR_STATIC int __t3_getdata_analysis(L7session_t3_private *p_st_private
                                  , Conntrack *p_st_conn
                                  , Frhash_header *p_st_hash_report
                                  , Apm_packet *p_st_packet
                                  , char *p_data
                                  , unsigned int ui_data_len)
{
    L7_fragment_t3 *p_st_fragment = NULL;
    unsigned int ui_left_len = 0;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_conn == NULL || p_st_hash_report == NULL
        || p_st_private->p_st_fragment == NULL || p_st_packet == NULL || p_data == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_fragment = p_st_private->p_st_fragment;
    if (ui_data_len == 0)
        return APM_L7_ANALYZE_TODO;

    // 创建bytebuffer
    if (p_st_fragment->p_st_data == NULL)
    {
        // 做成bytebuffer
        p_st_fragment->p_st_data = bytebuff_creat();
        if (p_st_fragment->p_st_data == NULL)
            goto err;
    }

    //上次packet还遗留的数据长度
    ui_left_len = p_st_fragment->u32_left_len;

    // 上次的数据包不完整
    if (ui_left_len)
    {
        // 本次数据还不够
        if (ui_left_len > ui_data_len)
        {
            if (ui_data_len != 0)
            {
                // 将本次数据存入buffer
                i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_data_len);
                if (i_ret != FR_SUCC)
                    goto err;
                p_st_fragment->u32_left_len -= ui_data_len;
            }
        }
        else
        {
            // 将剩余需要的数据存入buffer
            i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_left_len);
            if (i_ret != FR_SUCC)
                goto err;
            p_st_fragment->u32_left_len = 0;
        }

        if (p_st_fragment->p_st_data->ui_skip_len != 0)
            return APM_L7_ANALYZE_TODO;

        // 解析当前体数据
        if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
            i_ret = __t3_analysis_req(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
        else
            i_ret = __t3_analysis_resp(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto err;
        else if (i_ret == APM_L7_ANALYZE_TODO)
            return APM_L7_ANALYZE_TODO;
        else
        {
            if (p_st_fragment->p_st_data)
                bytebuff_free(&p_st_fragment->p_st_data);
            p_st_fragment->u32_total_len = 0;

            return i_ret;
        }
    }

    // 上次的数据包完整，开始新的数据包解析
    if (__ist3_longconn(p_st_conn, p_data, ui_data_len))
        p_st_private->is_login = 1;

    if (p_st_private->is_login == 0)
    {
        p_st_fragment->u32_total_len = ui_data_len;
        if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
            i_ret = __t3_session_start_request(p_st_private, p_data, ui_data_len);
        else
            i_ret = __t3_session_start_response(p_st_private, p_data, ui_data_len);

        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto err;
        else
            return APM_L7_ANALYZE_SUCC;
    }
    else
        p_st_fragment->u32_total_len = __t3_get_len(p_data, ui_data_len);
    if (p_st_fragment->u32_total_len == 0)
        goto err;

    // 数据长度不够
    if (p_st_fragment->u32_total_len > ui_data_len)
    {
        if (ui_data_len != 0)
        {
            i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_data_len);
            if (i_ret != FR_SUCC)
                goto err;
        }
        p_st_fragment->u32_left_len = p_st_fragment->u32_total_len - ui_data_len;
    }
    else
    {
        i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, p_st_fragment->u32_total_len);
        if (i_ret != FR_SUCC)
            goto err;
        p_st_fragment->u32_left_len = 0;
    }

    // 解析体数据
    if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
        i_ret = __t3_analysis_req(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
    else
        i_ret = __t3_analysis_resp(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
    if (i_ret == APM_L7_ANALYZE_FAIL)
        goto err;
    else if (i_ret == APM_L7_ANALYZE_TODO)
        return APM_L7_ANALYZE_TODO;
    else
    {
        if (p_st_fragment->p_st_data)
            bytebuff_free(&p_st_fragment->p_st_data);
        p_st_fragment->u32_total_len = 0;

        return i_ret;
    }

err:
    __t3_reset_private(p_st_private);
    return APM_L7_ANALYZE_FAIL;
}

/*!
 * 判断是否为t3数据包
 *
 * \param *p_st_conn       (Conntrack      连接信息)
 * \param *p_st_packet     (Apm_packet    数据包信息)
 *
 * \return APM_L7_IS_NO:不属于TCP协议\n
 *         APM_L7_IS_YES:属于TCP协议
 *
 */
int t3_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    char *p_data = NULL;
    unsigned int ui_data_len = 0;
    int i_ret = 0;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len == 0)
        return APM_L7_IS_NO;

    p_data = p_st_packet->p_payload;
    ui_data_len = p_st_packet->ui_payload_len;

    //方向明确
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_KNOWN)
    {
        //请求
        if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
        {
            if (__ist3_req(p_st_conn, p_data, ui_data_len))
                return APM_L7_IS_YES;
            else
            {
                if (__ist3_longconn(p_st_conn, p_data, ui_data_len))
                    return APM_L7_IS_YES;
            }
        }
        else //响应
        {
            if (__ist3_resp(p_st_conn, p_data, ui_data_len))
                return APM_L7_IS_YES;
        }

        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    else //方向不明确
    {
        if (__ist3_req(p_st_conn, p_data, ui_data_len) == 0 && __ist3_longconn(p_st_conn, p_data, ui_data_len) == 0)
        {
            if (__ist3_resp(p_st_conn, p_data, ui_data_len) == 0)
            {
                // 判断不出请求/响应/长连接请求
                i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
                if (i_ret == FR_SUCC)
                {
                    i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
                    if (i_ret != FR_SUCC)
                    {
                        frdbg("frcap_set_cs_srv failed\n");
                        return APM_L7_IS_NO;
                    }
                    return APM_L7_IS_YES;
                }
                i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
                if (i_ret == FR_SUCC)
                {
                    i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
                    if (i_ret != FR_SUCC)
                    {
                        frdbg("frcap_set_cs_srv failed\n");
                        return APM_L7_IS_NO;
                    }
                    return APM_L7_IS_YES;
                }
            }
            else // 响应
            {
                i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
                if (i_ret != FR_SUCC)
                {
                    frdbg("frcap_set_cs_srv failed\n");
                    return APM_L7_IS_NO;
                }
                return APM_L7_IS_YES;
            }
        }
        else // 请求
        {
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            if (i_ret != FR_SUCC)
            {
                frdbg("frcap_set_cs_srv failed\n");
                return APM_L7_IS_NO;
            }
            return APM_L7_IS_YES;
        }
    }

    return APM_L7_IS_NO;
}

/*!
 * t3 解析
 *
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_packet         (Apm_packet    数据包信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包不完整
 *
 */
int t3_analysis(Conntrack *p_st_conn
              , Apm_packet *p_st_packet
              , Frhash_header *p_st_hash_report)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_session *p_st_session = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //fin syn 包  销毁私有数据
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        t3_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    //p_session_private   分配内存
    if (p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = __t3_private_create();
        //内存分配失败
        if (p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    i_ret = __t3_getdata_analysis((L7session_t3_private *)p_st_session->p_session_private
                                , p_st_conn
                                , p_st_hash_report
                                , p_st_packet
                                , p_st_packet->p_payload
                                , p_st_packet->ui_payload_len);
    if (i_ret == APM_L7_ANALYZE_FAIL)
        return APM_L7_ANALYZE_FAIL;

    return i_ret;
}


/*!
 * t3 私有信息销毁
 *
 * \param *p_private_session    (t3的私有session数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败
 *
 */
int t3_session_destroy(void *p_private_session)
{
    L7session_t3_private *p_st_private = (L7session_t3_private *)p_private_session;

    if (p_st_private)
    {
        if (p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if (p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if (p_st_private->p_lst_req)
            frreport_body_l7list_free(&p_st_private->p_lst_req);

        if (p_st_private->p_lst_mq)
            frreport_body_l7list_free(&p_st_private->p_lst_mq);

        if (p_st_private->p_st_fragment)
            __t3_free_fragment(p_st_private->p_st_fragment);

        frfree(p_st_private->p_st_fragment);

        if (p_st_private->p_st_protocol_info)
            __t3_free_protocol_info(&p_st_private->p_st_protocol_info);

        if (p_st_private->p_st_session)
            __t3_free_session(&p_st_private->p_st_session);

        frfree(p_st_private);
    }
    return FR_SUCC;
}
